﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CSharp.Libs.WPF;
using System.Collections.ObjectModel;
using Exception = System.Exception;
using CSharp.Libs.Misc;
using System.Windows.Threading;
using Microsoft.Office.Interop.Outlook;
using Action = System.Action;

namespace Addins.Outlook
{
    /// <summary>
    /// Addins.Outlook.LinqQuery
    /// </summary>
    class LinqQueryViewModel : ViewModelBase, IDisposable
    {
        #region declarations
        private readonly Dispatcher _disp;
        private readonly LocalApplicationOptions _lao = new LocalApplicationOptions();
        private LinqQuery _lq;

        //Lists
        private readonly ObservableCollection<StoreItem> _ocStores = new ObservableCollection<StoreItem>();
        private ObservableCollection<MailItem> _ocMails = new ObservableCollection<MailItem>();

        //selected items
        private StoreItem _selectedStore;

        //strings

        //ints

        //bools
        private bool _fDisposed;

        #region constants
        private const string SELECTED_STORE_ITEM = "SelectedStoreItem";
        #endregion
        #endregion



        #region constructor / terminator
        public LinqQueryViewModel(
            Dispatcher disp)
        {
            //initialize auto properties
            ProgressMax = 100;
            Progress = 0;
            StatusText = "";

            //create basic references
            _disp = disp;
            _lq = new LinqQuery();

            //event subscriptions
            _lq.StoreListLoaded += _LqStoreListLoaded;
            _lq.MailsListReady += _LqMailsListReady;
            _lq.ReadingMailFolder += _LqReadingMailFolder;
        }

        #region IDisposable Member
        public void Dispose()
        {
            Dispose(true);
        }

        protected virtual void Dispose(
            bool disposing)
        {
            if (!_fDisposed)
            {
                if (disposing)
                {
                    //cleanup managed handles
                    if (_lq != null)
                    {
                        _lq.StoreListLoaded -= _LqStoreListLoaded;
                        _lq.MailsListReady -= _LqMailsListReady;
                        _lq.ReadingMailFolder -= _LqReadingMailFolder;
                        _lq.Dispose();
                    }
                    _lq = null;
                }

                _fDisposed = true;
            }
        }
        #endregion
        #endregion



        #region event handling
        void _LqStoreListLoaded(object sender)
        {
            //clear Collection
            _ClearStores();

            //cycle through stores in LinqQuery
            foreach (StoreItem str in _lq.Stores)
            {
                _AddStoreToStores(str);
            }

            //notify UI
            _NotifyStores();

            //get remembered store
            _GetSelectedStoreItem();
        }

        void _LqMailsListReady(object sender)
        {
            //reset status
            _ResetStatus();

            //show new status
            _SetProgress(0);
            //_SetProgressMax(_lq.Mails.Count());
            _SetStatusText("Putting mails to UI...");

            //put mails to UI
            _MailsToUi();

            //reset status
            _ResetStatus();
        }

        void _LqReadingMailFolder(object sender, ReadingMailFolderEventArgs rmfea)
        {
            _SetStatusText(String.Concat("Reading Folder ", rmfea.FolderName));
            Progress++;
            _SetProgress(Progress);
        }
        #endregion



        #region private functions
        #region store list
        /// <summary>generates the list of stores available (linked into outlook)
        /// </summary>
        /// <history>created  18.06.2012</history>
        //private void _CreateStoreList()
        //{
        //    //clear collection
        //    _ocStores.Clear();

        //    //cycle through stores in session
        //    foreach (Store str in _outlook.Session.Stores)
        //    {
        //        _ocStores.Add(new StoreItem(str.DisplayName, str.FilePath));
        //    }

        //    //notify UI
        //    OnPropertyChanged("Stores");
        //}

        /// <summary>
        /// 
        /// </summary>
        /// <history>created  18.06.2012</history>
        private void _GetSelectedStoreItem()
        {
            string strSelectedDisplayName = _lao.GetOption(SELECTED_STORE_ITEM);

            //breakout if nothing is saved
            if (strSelectedDisplayName.Trim() == "")
            {
                return;
            }

            //find store item
            foreach (StoreItem storeItem in _ocStores)
            {
                if (storeItem.DisplayName == strSelectedDisplayName)
                {
                    SelectedStore = storeItem;
                    _NotifySelectedStore();
                    break;
                }
            }
        }
        #endregion

        #region mails
        /// <summary>
        /// 
        /// </summary>
        /// <history>created  19.06.2012</history>
        private void _MailsToUi() 
        {
            _ClearMails();
            _NotifyMails();

            foreach (MailItem mailItem in _lq.Mails)
            {
                Progress++;
                _SetProgress(Progress);
                _AddMailToMails(mailItem);
            }

            _NotifyMails();
            _SetProgress(0);
        }
        #endregion

        #region status
        /// <summary>
        /// 
        /// </summary>
        /// <history>created  21.06.2012</history>
        private void _ResetStatus()
        {
            _SetProgressMax(100);
            _SetProgress(0);
            _SetStatusText("");
        }
        #endregion

        #region UI threads
        /// <summary>clears the StoreItems collection
        /// </summary>
        /// <history>created  20.06.2012</history>
        private void _ClearStores()
        {
            _disp.Invoke((Action)(() => _ocStores.Clear()));
        }

        /// <summary>adds storeItem to the StoreItems collection
        /// </summary>
        /// <history>created  20.06.2012</history>
        private void _AddStoreToStores(
            StoreItem storeItem)
        {
            _disp.Invoke((Action)(() => _ocStores.Add(storeItem)));
        }

        /// <summary>notifies UI that binding source has changed
        /// </summary>
        /// <history>created  20.06.2012</history>
        private void _NotifyStores()
        {
            _disp.Invoke((Action)(() => OnPropertyChanged("Stores")));
        }

        /// <summary>notifies UI that binding source has changed
        /// </summary>
        /// <history>created  20.06.2012</history>
        private void _NotifySelectedStore()
        {
            _disp.Invoke((Action)(() => OnPropertyChanged("SelectedStore")));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <history>created  21.06.2012</history>
        private void _ClearMails()
        {
            _disp.Invoke((System.Action)(() => _ocMails.Clear()));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="mailItem"></param>
        /// <history>created  21.06.2012</history>
        private void _AddMailToMails(
            MailItem mailItem)
        {
            _disp.Invoke((System.Action)(() => _ocMails.Add(mailItem)));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <history>created  21.06.2012</history>
        private void _NotifyMails()
        {
            _disp.Invoke((System.Action)(() => OnPropertyChanged("Mails")));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="intProgressMax"></param>
        /// <history>created  21.06.2012</history>
        private void _SetProgressMax(
            int intProgressMax)
        {
            _disp.Invoke((System.Action)delegate
            {
                ProgressMax = intProgressMax;
                OnPropertyChanged("ProgressMax");
            });
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="intProgress"></param>
        /// <history>created  21.06.2012</history>
        private void _SetProgress(
            int intProgress)
        {
            _disp.Invoke((System.Action) delegate
                                         {
                                             Progress = intProgress;
                                             if (Progress > ProgressMax)
                                             {
                                                 Progress = 0;
                                             }
                                             OnPropertyChanged("Progress");
                                         });
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="strText"></param>
        /// <history>created  21.06.2012</history>
        private void _SetStatusText(
            string strText)
        {
            _disp.Invoke((System.Action) delegate
                                         {
                                             StatusText = strText;
                                             OnPropertyChanged("StatusText");
                                         });
        }
        #endregion
        #endregion



        #region interface
        #region properties
        #region stores
        /// <summary>lists all available stores (.pst)
        /// </summary>
        /// <history>created  18.06.2012</history>
        public ObservableCollection<StoreItem> Stores
        {
            get
            {
                return _ocStores;
            }
        }

        /// <summary>represents the selected StoreItem of the Stores collection
        /// </summary>
        /// <history>created  18.06.2012</history>
        public StoreItem SelectedStore
        {
            get
            {
                return _selectedStore;
            }
            set
            {
                //set value
                _selectedStore = value;
                
                //write options
                _lao.SetOption(SELECTED_STORE_ITEM, _selectedStore.DisplayName);
                
                //get mails
                //_GetMailsOfStore();
                _lq.RefreshMailsList(_selectedStore.DisplayName);
            }
        }
        #endregion

        #region mails
        /// <summary>
        /// 
        /// </summary>
        /// <history>created  18.06.2012</history>
        public ObservableCollection<MailItem> Mails
        {
            get
            {
                return _ocMails;
            }
        }
        #endregion

        #region status
        /// <summary>
        /// 
        /// </summary>
        /// <history>created  21.06.2012</history>
        public int ProgressMax { get; set; }

        /// <summary>
        /// 
        /// </summary>
        /// <history>created  21.06.2012</history>
        public int Progress { get; set; }

        /// <summary>
        /// 
        /// </summary>
        /// <history>created  21.06.2012</history>
        public string StatusText { get; set; }
        #endregion
        #endregion

        #region methods
        #endregion
        #endregion
    }
}
